<template>
  <div class="article-container">
    <div class="article-content">
      <div class="markdown-body" v-html="renderedContent"></div>
    </div>
    <div class="article-toc" v-if="toc.length > 0">
      <div class="toc-title">目录</div>
      <el-scrollbar height="calc(100vh - 200px)">
        <ul class="toc-list">
          <li
            v-for="item in toc"
            :key="item.id"
            :class="{ active: activeHeading === item.id }"
            :style="{ paddingLeft: `${item.level * 12}px` }"
            @click="scrollToHeading(item.id)"
          >
            {{ item.text }}
          </li>
        </ul>
      </el-scrollbar>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, watch } from 'vue'
import MarkdownIt from 'markdown-it'
import toc from 'markdown-it-toc-done-right'

interface TocItem {
  id: string
  text: string
  level: number
}

const props = defineProps<{
  content: string
}>()

const md = new MarkdownIt({
  html: true,
  linkify: true,
  typographer: true
}).use(toc)

const renderedContent = ref('')
const tocItems = ref<TocItem[]>([])
const activeHeading = ref('')

const generateToc = () => {
  const headings: TocItem[] = []
  const headingRegex = /<h([1-6])[^>]*id="([^"]*)"[^>]*>(.*?)<\/h\1>/g
  let match

  while ((match = headingRegex.exec(renderedContent.value)) !== null) {
    headings.push({
      level: parseInt(match[1]),
      id: match[2],
      text: match[3].replace(/<[^>]+>/g, '')
    })
  }

  tocItems.value = headings
}

const scrollToHeading = (id: string) => {
  const element = document.getElementById(id)
  if (element) {
    element.scrollIntoView({ behavior: 'smooth' })
  }
}

const updateActiveHeading = () => {
  const headings = tocItems.value.map(item => ({
    id: item.id,
    element: document.getElementById(item.id)
  }))

  const scrollPosition = window.scrollY

  for (let i = headings.length - 1; i >= 0; i--) {
    const heading = headings[i]
    if (heading.element && heading.element.offsetTop <= scrollPosition + 100) {
      activeHeading.value = heading.id
      break
    }
  }
}

onMounted(() => {
  renderedContent.value = md.render(props.content)
  generateToc()
  window.addEventListener('scroll', updateActiveHeading)
})

watch(() => props.content, () => {
  renderedContent.value = md.render(props.content)
  generateToc()
})
</script>

<style scoped>
.article-container {
  display: flex;
  gap: 40px;
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.article-content {
  flex: 1;
  min-width: 0;
}

.article-toc {
  width: 280px;
  position: sticky;
  top: 80px;
  height: fit-content;
  background-color: var(--el-bg-color);
  border-radius: 8px;
  padding: 16px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.toc-title {
  font-size: 16px;
  font-weight: bold;
  margin-bottom: 16px;
  color: var(--el-text-color-primary);
}

.toc-list {
  list-style: none;
  padding: 0;
  margin: 0;
}

.toc-list li {
  margin: 8px 0;
  font-size: 14px;
  color: var(--el-text-color-regular);
  cursor: pointer;
  transition: all 0.3s;
}

.toc-list li:hover {
  color: var(--el-color-primary);
}

.toc-list li.active {
  color: var(--el-color-primary);
  font-weight: bold;
}

:deep(.markdown-body) {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  line-height: 1.6;
  color: var(--el-text-color-primary);
}

:deep(.markdown-body h1),
:deep(.markdown-body h2),
:deep(.markdown-body h3),
:deep(.markdown-body h4),
:deep(.markdown-body h5),
:deep(.markdown-body h6) {
  margin-top: 24px;
  margin-bottom: 16px;
  font-weight: 600;
  line-height: 1.25;
}

:deep(.markdown-body p) {
  margin-bottom: 16px;
}

:deep(.markdown-body code) {
  padding: 0.2em 0.4em;
  margin: 0;
  font-size: 85%;
  background-color: var(--el-fill-color-light);
  border-radius: 3px;
}

:deep(.markdown-body pre) {
  padding: 16px;
  overflow: auto;
  font-size: 85%;
  line-height: 1.45;
  background-color: var(--el-fill-color-light);
  border-radius: 3px;
}

@media (max-width: 768px) {
  .article-container {
    flex-direction: column;
  }

  .article-toc {
    width: 100%;
    position: static;
  }
}
</style> 